#include "iap.h"
#include "bsp_stmflash.h"
#include "UsartFrame_STM32.h"
#include "cantransmitter.h"
#include "usarttransmitter.h"
#include "communication.h"

iapfun jump2app;
uint32_t iapbuf[512] = {0};

void iap_write_appbin(uint32_t appxaddr,uint8_t *appbuf,uint32_t appsize)
{
	uint32_t t;
	uint16_t i=0;
	uint32_t temp;
	uint32_t fwaddr=appxaddr;
	uint8_t *dfu=appbuf;
	for(t=0;t<appsize;t+=4)
	{
		temp=(uint32_t)dfu[3]<<24;   
		temp|=(uint32_t)dfu[2]<<16;    
		temp|=(uint32_t)dfu[1]<<8;
		temp|=(uint32_t)dfu[0];	  
		dfu+=4;
		iapbuf[i++]=temp;	    
		if(i==512)
		{
			i=0;
			STMFLASH_Write(fwaddr,iapbuf,512);
			fwaddr+=2048;
		}
	}
	if(i)STMFLASH_Write(fwaddr,iapbuf,i);
}


void iap_load_app(uint32_t appxaddr)
{
	if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)//确定地址appxaddr里面储存的是栈顶地址，
												   //也就是内部程序SRAM边界
	{
		INTX_DISABLE();//关闭所有中断(但是不包括fault和NMI中断)
		jump2app=(iapfun)*(vu32*)(appxaddr+4);//前四字节为中断向量表
											  //指向用户程序复位函数地址
		__disable_irq();//关闭总中断，在app中必须开启
		//关闭外设
		USART_ITConfig(USART1, USART_IT_IDLE, DISABLE);
		USART_DMACmd(USART1,USART_DMAReq_Tx,DISABLE);
		DMA_ITConfig(DMA2_Stream7,DMA_IT_TC,DISABLE);
		DMA_Cmd(DMA2_Stream7,DISABLE);
		USART_DeInit(USART1);
		
		CAN_ITConfig(CAN1,CAN_IT_FMP0,DISABLE);
		CAN_ITConfig(CAN1,CAN_IT_FMP1,DISABLE);
		CAN_ITConfig(CAN1,CAN_IT_TME,DISABLE);
		
		CAN_ITConfig(CAN2,CAN_IT_FMP0,DISABLE);
		CAN_ITConfig(CAN2,CAN_IT_FMP1,DISABLE);
		CAN_ITConfig(CAN2,CAN_IT_TME,DISABLE);
		
		MSR_MSP(*(vu32*)appxaddr);//设置用户程序栈指针
		__DSB();
		__ISB();
		jump2app();//跳转到用户指定程序
	}
}	 

IAPFALG Iapflag = {0};

void Iap_Process(void)
{
	static uint8_t runcnt = 0;
	if(!Iapflag.rec_iap_flag){
		runcnt++;
		if(runcnt>250){//开机持续250节拍没有收到固件升级信息，直接升级
			iap_load_app(FLASH_APP1_ADDR);
		}
	}
	else{
		Iapflag.overtime++;
		if(Iapflag.overtime>250){
			iap_load_app(FLASH_APP1_ADDR);//通讯超时，直接升级
		}
	}
	if(Iapflag.jump_flag){
		IapSucessReturn();//返回成功给上层
		iap_load_app(FLASH_APP1_ADDR);//CRC32 check 通过，升级固件
	}
}

uint8_t IAP_SRAM_BUF[IAPSRAMLEN] = {0};
void IapPacketCombine(uint8_t *buf,uint8_t len,uint16_t index)
{
	uint8_t i = 0;
//	uint32_t crc32 = 0;
	for(i=0;i<len;i++)
	{
		IAP_SRAM_BUF[index*len+i] = buf[i];	
	}
	
	if((index+1) == Iapflag.totalindex){
		if(!CRC_STM32Check(IAP_SRAM_BUF,Iapflag.applen,Iapflag.crc32)){
			IapErrorReturn();//返回错误给上层
		}
		else{
			Iapflag.jump_flag = 1;
		}
	}
}

void IapDataPrase(uint8_t *data,uint16_t len)
{
	if(len<4){return;}
	if(data[0] == 0XF1 && (data[1]&0XE0) && (data[1]&IAP_ID)){
		Iapflag.rec_iap_flag = 1;
		Iapflag.applen = (uint32_t)data[2]<<8|data[3];
		Iapflag.totalindex	= Iapflag.applen/IAP_BUF_LEN;
		Iapflag.crc32 = ((uint32_t)data[4]<<24)|((uint32_t)data[5]<<16)|((uint32_t)data[6]<<8)|(data[7]);
	}
	else{
		Iapflag.overtime = 0;
		IapPacketCombine(data,len,Iapflag.appindex);
		Iapflag.appindex++;
	}
}

void IapErrorReturn(void)
{
//	uint8_t buf[8] = {0XE0,0XE1,0XE2,0XE3,0XE4,0XE5,0XE6,0XE7};
	#if USE_CAN_NOT_UART
//		CanBufferPush(MAIN_BOARD_FROM_Z,buf);
	#else
		UsartBufferPush(MAIN_BOARD_FROM_Z,buf);
	#endif
}

void IapSucessReturn(void)
{
//	uint8_t buf[8] = {0XF0,0XF1,0XF2,0XF3,0XF4,0XF5,0XF6,0XF7};
	#if USE_CAN_NOT_UART
////		CanBufferPush(MAIN_BOARD_FROM_Z,buf);
	#else
		UsartBufferPush(MAIN_BOARD_FROM_Z,buf);
	#endif
}

void reset2isp(void)
{
	__set_FAULTMASK(1);
	NVIC_SystemReset();
}

